/*----------------------------------------------------------------------------------------
*
*  Copyright 2019, Gao Hai Hui, <fromzeropoint@126.com>.  All rights reserved.
*  https://gitee.com/helloworldghh/xoskit.git
*  Use of this source code is governed by a MIT license
*  that can be found in the License file.
*
----------------------------------------------------------------------------------------*/
#include "../import/head.h"
#include "../data_struct/head.h"
#include "../macro/head.h"
#include "rsa_impl.h"
#include "rsa_mgr.h"
#include "mgr.h"

namespace xos_encrypt
{
    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    static rsa_impl::ITEM_DATA xos_item_data;

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    rsa_impl::rsa_impl()
    {
        init_data();
    }

    rsa_impl::~rsa_impl()
    {}

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // public method

    int rsa_impl::get_xos_item_data( ITEM_DATA*& item_ptr )
    {
        int ret = 0;
        xos_item_data.set_container( mgr::container() );
        item_ptr = &xos_item_data;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int rsa_impl::padding_step( f_rsa lpFun, RSA * pRSA, char * lpszOutBuf, const char * lpszInBuf, int nInLen )
    {
        int nRetLen = 0;
        int ret = 0;

        int nStep = m_pMgr->m_nRsaLen;
        int nLen = nInLen;
        int nPos = 0;

        const unsigned char * pIn = ( const unsigned char * )lpszInBuf;
        unsigned char * pOut = ( unsigned char * )lpszOutBuf;

        while( ( nLen > 0 ) && ( 0 == ret ) )
        {
            int len = nLen > nStep ? nStep : nLen;
            int r = lpFun( len, pIn + nPos, pOut + nPos, pRSA, RSA_PKCS1_PADDING );
            nLen -= len;
            nPos += len;
            if( -1 != r )
            {
                nRetLen += r;
            }
            else
            {
                ret = 1;
            }
        }

        if( 0 != ret )
        {
            nRetLen = -1;
        }

        return nRetLen;
    }

    int rsa_impl::init_data()
    {
        int ret = 0;
        m_bPrivate = true;
        m_pMgr = 0;
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    int rsa_impl::set_mgr( rsa_mgr* pMgr )
    {
        int ret = 0;
        m_pMgr = pMgr;
        return ret;
    }

    int rsa_impl::init()
    {
        int ret = 0;
        return ret;
    }

    int rsa_impl::term()
    {
        int ret = 0;
        init_data();
        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // other : 返回长度
    //    -1 : 失败
    int rsa_impl::encode( char * lpszOutBuf, const char * lpszInBuf, int nInLen )
    {
        int ret = 0;

        RSA * pPrivate = ( RSA * )m_pMgr->m_pPrivateRSA;
        RSA * pPublic = ( RSA * )m_pMgr->m_pPublicRSA;

        if( m_bPrivate )
        {
            ret = padding_step( RSA_private_encrypt, pPrivate, lpszOutBuf, lpszInBuf, nInLen );
        }
        else
        {
            ret = padding_step( RSA_public_encrypt, pPublic, lpszOutBuf, lpszInBuf, nInLen );
        }

        return ret;
    }

    // other : 返回长度
    //    -1 : 失败
    int rsa_impl::decode( char * lpszOutBuf, const char * lpszInBuf, int nInLen )
    {
        int ret = 0;

        RSA * pPrivate = ( RSA * )m_pMgr->m_pPrivateRSA;
        RSA * pPublic = ( RSA * )m_pMgr->m_pPublicRSA;

        if( m_bPrivate )
        {
            ret = padding_step( RSA_private_decrypt, pPrivate, lpszOutBuf, lpszInBuf, nInLen );
        }
        else
        {
            ret = padding_step( RSA_public_decrypt, pPublic, lpszOutBuf, lpszInBuf, nInLen );
        }

        return ret;
    }

    /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    // 

    // encode with buf
    int rsa_impl::encode( xos_box::i_buf * pOutBuf, xos_box::i_buf * pInBuf )
    {
        int ret = 0;

        int nOutLen = 0;
        int nInLen = 0;
        char * pIn = pInBuf->get_data( 0, 0, 0, &nInLen );
        char * pOut = pOutBuf->get_data( 0, 0, 0, 0 );

        nOutLen = encode( pOut, pIn, nInLen );

        if( nOutLen > 0 )
        {
            pOutBuf->set_len( nOutLen );
            ret = nOutLen;
        }
        else
        {
            ret = -1;
        }

        return ret;
    }

    int rsa_impl::decode( xos_box::i_buf * pOutBuf, xos_box::i_buf * pInBuf )
    {
        int ret = 0;

        int nOutLen = 0;
        int nInLen = 0;
        char * pIn = pInBuf->get_data( 0, 0, 0, &nInLen );
        char * pOut = pOutBuf->get_data( 0, 0, 0, 0 );

        nOutLen = decode( pOut, pIn, nInLen );

        if( nOutLen > 0 )
        {
            pOutBuf->set_len( nOutLen );
            ret = nOutLen;
        }
        else
        {
            ret = -1;
        }

        return ret;
    }

    // encode with list
    int rsa_impl::encode( xos_box::i_list * pOutList, xos_box::i_list * pInList )
    {
        int ret = 0;

        xos_box::i_buf * pIn = 0;

        while( ( 0 == ret ) && ( pIn = ( xos_box::i_buf * )pInList->front( 0 ) ) )
        {
            xos_box::i_buf * pOut = mgr::container()->box()->buf();
            int len = encode( pOut, pIn );
            if( len > 0 )
            {
                xos_stl::release_interface( pIn );
                pOutList->push_back( pOut );
                pInList->pop_front();
                pOut = 0;
            }
            else
            {
                ret = 1;
            }
            xos_stl::release_interface( pOut );
        }

        return ret;
    }

    int rsa_impl::decode( xos_box::i_list * pOutList, xos_box::i_list * pInList )
    {
        int ret = 0;

        xos_box::i_buf * pIn = 0;

        while( ( 0 == ret ) && ( pIn = ( xos_box::i_buf * )pInList->front( 0 ) ) )
        {
            xos_box::i_buf * pOut = mgr::container()->box()->buf();
            int len = decode( pOut, pIn );
            if( len > 0 )
            {
                xos_stl::release_interface( pIn );
                pOutList->push_back( pOut );
                pInList->pop_front();
                pOut = 0;
            }
            else
            {
                ret = 1;
            }
            xos_stl::release_interface( pOut );
        }

        return ret;
    }

    int rsa_impl::set_type( bool bPrivate )
    {
        int ret = 0;
        m_bPrivate = bPrivate;
        return ret;
    }

} // xos_encrypt
